package modelado.datos;

import java.util.Map;
import java.util.Set;

import utiles.FactoriaDeColecciones;
import utiles.Par;
import utiles.ParImpl;
import utiles.SituacionIlegal;

import modelado.datos.elementos.Arista;
import modelado.datos.elementos.AristaImpl;
import modelado.datos.elementos.Elemento;
import modelado.datos.elementos.ElementoConVariasInstancias;
import modelado.datos.elementos.GestionaVertice;
import modelado.datos.elementos.Vertice;

public class DatosDiscretosAbstracto implements DatosDiscretos,
		GestionaDatosDiscretos {
	private static Set<Elemento> elementosConVariasInstancias = FactoriaDeColecciones
			.creaSet();
	private static Set<Elemento> vertices = FactoriaDeColecciones.creaSet();
	private static Map<Integer, Elemento> mapElementos = FactoriaDeColecciones
			.creaMap();
	private static Map<Par<Integer>, Arista> mapAristas = FactoriaDeColecciones
			.creaMap();
	private static Set<Elemento> aristas = FactoriaDeColecciones.creaSet();
	private static Set<Elemento> nodosIniciales = FactoriaDeColecciones
			.creaSet();
	private static Set<Elemento> nodosFinales = FactoriaDeColecciones.creaSet();

	public DatosDiscretosAbstracto() {
	}

	public Elemento getElemento(Integer n) {
		if (!mapElementos.containsKey(n))
			throw new SituacionIlegal(
					"El c�digo no corresponde a ning�n elemento " + n);
		return mapElementos.get(n);
	}

	public Arista getArista(Elemento e1, Elemento e2) {
		Par<Integer> p = new ParImpl<Integer>(e1.getCodigo(), e2.getCodigo());
		Arista a = mapAristas.get(p);
		return a;
	}

	public Set<Elemento> getElementosConVariasInstancias() {
		return elementosConVariasInstancias;
	}

	public Set<Elemento> getVertices() {
		return vertices;
	}

	public Set<Elemento> getAristas() {
		return aristas;
	}

	private void addElemento(Elemento e) {
		if (mapElementos.containsKey(e.getCodigo()))
			throw new SituacionIlegal("El elemento est� repetido " + e);
		mapElementos.put(e.getCodigo(), e);
	}

	public void addElementoConVariasInstancias(ElementoConVariasInstancias e) {
		addElemento(e);
		elementosConVariasInstancias.add(e);
	}

	public void addVertice(Vertice v) {
		addElemento(v);
		vertices.add(v);
	}

	public boolean hayArista(Elemento e1, Elemento e2) {
		Par<Integer> p = new ParImpl<Integer>(e1.getCodigo(), e2.getCodigo());
		return mapAristas.containsKey(p);
	}

	public void addArista(Vertice e1, Vertice e2, Integer peso) {
		((GestionaVertice) e1).addVecino(e2);
		Par<Integer> p = new ParImpl<Integer>(e1.getCodigo(), e2.getCodigo());
		Arista a = new AristaImpl(e1, e2, peso);
		aristas.add(a);
		mapAristas.put(p, a);
	}

	public void addAristas(Vertice e1, Vertice e2, Integer peso) {
		addArista(e1, e2, peso);
		addArista(e2, e1, peso);
	}

	public boolean hayNodosIniciales() {
		;
		return !(nodosIniciales.isEmpty());
	}

	public Set<Elemento> getNodosIniciales() {
		return nodosIniciales;
	}

	public void addNodoInicial(Vertice e) {
		nodosIniciales.add(e);
	}

	public boolean hayNodosFinales() {
		return !(nodosFinales.isEmpty());
	}

	public void addNodoFinal(Vertice e) {
		nodosFinales.add(e);
	}

	public Set<Elemento> getNodosFinales() {
		return nodosFinales;
	}
}
